//
//  LcPreconditions.m
//  18Birdies
//
//  Created by Lc on 15/3/24.
//  Copyright (c) 2015年 Lc. All rights reserved.
//

#import "LcFoundationException.h"
#import "LcPersistenceCenter.h"
#import "LcPreconditions.h"
#import "LcReflection.h"
#import "LcSecurityCenter.h"
#import "NSDate+Lc.h"
#import "NSString+Lc.h"

@implementation LcPreconditions

+ (void)checkNotNull:(id)object
                file:(const char*)file
              method:(const char*)method
                line:(long)line {
  if (object == nil) {
    [self error:@"cannot be null" file:file method:method line:line];
  }
}

+ (void)checkNotEmpty:(NSObject*)object
                 file:(const char*)file
               method:(const char*)method
                 line:(long)line {
  if ([LcReflection isType:NSStringFromClass(object.class)
               KindOfClass:NSString.class]) {
    NSString* string = (NSString*)object;
    if (string.length == 0) {
      [self error:@"cannot be empty" file:file method:method line:line];
    }
  } else if ([LcReflection isCollectionType:NSStringFromClass(object.class)]) {
    id collection = object;
    if ([collection count] == 0) {
      [self error:@"cannot be empty" file:file method:method line:line];
    }
  } else if ([LcReflection isType:NSStringFromClass(object.class)
                      KindOfClass:NSData.class]) {
    NSData* data = (NSData*)object;
    if (data.length == 0) {
      [self error:@"cannot be empty" file:file method:method line:line];
    }
  } else {
    [self checkNotNull:object file:file method:method line:line];
  }
}

+ (void)checkTrue:(BOOL)condition
             file:(const char*)file
           method:(const char*)method
             line:(long)line {
  if (!condition) {
    [self error:@"cannot be false" file:file method:method line:line];
  }
}

+ (void)checkFalse:(BOOL)condition
              file:(const char*)file
            method:(const char*)method
              line:(long)line {
  if (condition) {
    [self error:@"cannot be true" file:file method:method line:line];
  }
}

+ (void)fail:(NSString*)reason
        file:(const char*)file
      method:(const char*)method
        line:(long)line {
  [self error:reason file:file method:method line:line];
}

+ (void)debugFail:(NSString*)reason
             file:(const char*)file
           method:(const char*)method
             line:(long)line {
#ifdef DEBUG
  [self error:reason file:file method:method line:line];
#endif
}

+ (void)checkIsMainThread:(NSString*)reason
                     file:(const char*)file
                   method:(const char*)method
                     line:(long)line {
  if (![NSThread isMainThread]) {
    [self error:@"should be main thread" file:file method:method line:line];
  }
}

+ (void)checkCollection:(id)collection
       withElementClazz:(Class)elementClazz
    andAllowNullElement:(BOOL)allowNullElement
                   file:(const char*)file
                 method:(const char*)method
                   line:(long)line {
  if (collection == nil) {
    return;
  }
  LC_CHECK_NOT_NULL(elementClazz);
  if (![LcReflection isCollectionType:NSStringFromClass([collection class])]) {
    [self error:@"not collection type" file:file method:method line:line];
  }
  for (id object in collection) {
    if (object == [NSNull null]) {
      if (!allowNullElement) {
        [self error:@"collection cannot contain null element"
               file:file
             method:method
               line:line];
      }
    } else if (![object isKindOfClass:elementClazz]) {
      [self
           error:[NSString stringWithFormat:@"element type is %@, should be %@",
                                            NSStringFromClass([object class]),
                                            NSStringFromClass(elementClazz)]
            file:file
          method:method
            line:line];
    }
  }
}

+ (void)error:(NSString*)message
         file:(const char*)file
       method:(const char*)method
         line:(long)line {
  NSString* fileName = [[NSString stringWithUTF8String:file] lastPathComponent];
  NSString* log = [NSString
      stringWithFormat:@"date=%@, message=%@, file=%@, method=%s, line=%ld",
                       [NSDate date], message, fileName, method, line];
  [[LcPersistenceCenter sharedInstance]
      saveData:log.toData
        toFile:[NSString stringWithFormat:@"crashes/%lld.log",
                                          [NSDate currentTimeMillis]]];
#ifdef DEBUG
  @throw [LcFoundationException
      exceptionWithReason:
          [NSString stringWithFormat:@"%@, file=%@, method=%s, line=%ld",
                                     message, fileName, method, line]];
#endif
}

@end
